package org.example.oss.service.impl;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.*;
import org.example.core.exception.CustomException;
import org.example.core.exception.ExceptionCode;
import org.example.oss.properties.OssFrontProperties;
import org.example.oss.properties.OssProperties;
import org.example.oss.service.OssService;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author 小杰_cc
 * @version 1.0
 */
@Service
public class OssServiceImpl implements OssService {

    @Autowired
    private OssProperties ossProperties;

    @Autowired
    private OssFrontProperties ossFrontProperties;

    // 获取上传凭证
    @Override
    public Map<String, String> getPolicy() {
        return policy(ossProperties.getAccessKeyId(), ossProperties.getSecretAccessKey(), ossProperties.getEndpoint(), ossProperties.getBucketName());
    }

    // 删除单个图片
    @Override
    public void remove(String name){
        // Endpoint以华东1（杭州）为例，其它Region请按实际情况填写。
        String endpoint = ossProperties.getEndpoint();
        // 从环境变量中获取访问凭证。运行本代码示例之前，请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。这里为了方便我就不放环境变量了
        // EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 填写Bucket名称，例如examplebucket。
        String bucketName = ossProperties.getBucketName();
        // 填写文件完整路径。文件完整路径中不能包含Bucket名称。

        // 创建OSSClient实例。
        // OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);
        OSS ossClient = new OSSClientBuilder().build(endpoint,ossProperties.getAccessKeyId(),ossProperties.getSecretAccessKey());
        try {
            // 删除文件或目录。如果要删除目录，目录必须为空。
            VoidResult result = ossClient.deleteObject(bucketName, name);
            if (result.getResponse().getStatusCode() != 204){
                throw new CustomException(ExceptionCode.REMOVE_ERROR.getCode(),ExceptionCode.REMOVE_ERROR.getMsg());
            }
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    @Override
    public void removes(List<String> keys) {
        // Endpoint以华东1（杭州）为例，其它Region请按实际情况填写。
        String endpoint = ossProperties.getEndpoint();
        // 从环境变量中获取访问凭证。运行本代码示例之前，请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        // EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();

        // 为了方便我放配置中心
        // 填写Bucket名称，例如examplebucket。
        String bucketName = ossProperties.getBucketName();

        // 创建OSSClient实例。放环境变量的写法
        //OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);

        // 放配置中心的写法
        OSS ossClient = new OSSClientBuilder().build(endpoint,ossProperties.getAccessKeyId(),ossProperties.getSecretAccessKey());

        try {
            // 删除文件。
            // 填写需要删除的多个文件完整路径。文件完整路径中不能包含Bucket名称。
//            List<String> keys = Arrays.asList(names);

            // 参考地址：https://help.aliyun.com/zh/oss/developer-reference/delete-objects-4?spm=a2c4g.11186623.0.0.2f6d3ba3XQVf0e
            DeleteObjectsResult deleteObjectsResult = ossClient.deleteObjects(new DeleteObjectsRequest(bucketName).withKeys(keys).withEncodingType("url").withQuiet(true));
            // 简单模式，返回的是删除失败的列表
            List<String> deletedObjects = deleteObjectsResult.getDeletedObjects();
            // System.out.println(deletedObjects.toString());
            if (deletedObjects != null && !deletedObjects.isEmpty()) {
                // 删除失败
                throw new CustomException(ExceptionCode.REMOVE_ERROR.getCode(),ExceptionCode.REMOVE_ERROR.getMsg());
            }
        }catch (OSSException oe){
            System.out.println(oe.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 用户上传获取凭证
     * @return
     */
    @Override
    public Map<String, String> getFrontPolicy() {
        return policy(ossFrontProperties.getAccessKeyId(), ossFrontProperties.getSecretAccessKey(), ossFrontProperties.getEndpoint(), ossFrontProperties.getBucketName());
    }

    @Nullable
    private static Map<String, String> policy(String accessId, String accessKey, String endpoint, String bucket) {
        String host = "https://" + bucket + "." + endpoint;

        String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String dir = format + "/";

        Map<String, String> respMap = null;
        // 创建ossClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessId, accessKey);
        try {
            long expireTime = 60;
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            Date expiration = new Date(expireEndTime);
            PolicyConditions policyConds = new PolicyConditions();
            policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
            policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);

            String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
            byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8);
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String postSignature = ossClient.calculatePostSignature(postPolicy);

            respMap = new LinkedHashMap<String, String>();
            respMap.put("OSSAccessKeyId", accessId);
            respMap.put("policy", encodedPolicy);
            respMap.put("signature", postSignature);
            respMap.put("dir", dir);
            respMap.put("host", host);
            respMap.put("expire", String.valueOf(expireEndTime / 1000));
            // respMap.put("expire", formatISO8601Date(expiration));

        } catch (Exception e) {
            // Assert.fail(e.getMessage());
            System.out.println(e.getMessage());
        }finally {
            ossClient.shutdown();
        }
        return respMap;
    }
}
